package net.jgrm.product.service.impl;

import lombok.extern.slf4j.Slf4j;
import net.jgrm.product.service.IProductViewService;
import net.jgrm.redisadvanced.service.RedisHyperLogLogService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 商品访问统计服务实现类
 * 使用Redis HyperLogLog实现高效的PV/UV统计
 */
@Slf4j
@Service
public class ProductViewServiceImpl implements IProductViewService {

    @Autowired
    private RedisHyperLogLogService redisHyperLogLogService;

    private static final String PV_KEY_PREFIX = "product:pv:";
    private static final String UV_KEY_PREFIX = "product:uv:";
    private static final String DAILY_PV_KEY_PREFIX = "product:daily:pv:";
    private static final String DAILY_UV_KEY_PREFIX = "product:daily:uv:";

    // 统计数据保存7天
    private static final long EXPIRE_DAYS = 7;

    @Override
    public void recordProductView(Long productId, String userIdentifier, String sessionId) {
        try {
            String today = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));

            // 记录总PV（使用sessionId + timestamp确保每次访问都被记录）
            String pvValue = sessionId + ":" + System.currentTimeMillis();
            String pvKey = PV_KEY_PREFIX + productId;
            String dailyPvKey = DAILY_PV_KEY_PREFIX + productId + ":" + today;

            // 记录总UV（使用用户标识确保独立访客统计）
            String uvKey = UV_KEY_PREFIX + productId;
            String dailyUvKey = DAILY_UV_KEY_PREFIX + productId + ":" + today;

            // 添加到HyperLogLog
            redisHyperLogLogService.add(pvKey, pvValue);
            redisHyperLogLogService.add(dailyPvKey, pvValue);
            redisHyperLogLogService.add(uvKey, userIdentifier);
            redisHyperLogLogService.add(dailyUvKey, userIdentifier);

            // 设置今日统计的过期时间
            redisHyperLogLogService.expire(dailyPvKey, EXPIRE_DAYS, TimeUnit.DAYS);
            redisHyperLogLogService.expire(dailyUvKey, EXPIRE_DAYS, TimeUnit.DAYS);

            log.debug("记录商品访问: productId={}, userIdentifier={}, sessionId={}",
                    productId, userIdentifier, sessionId);

        } catch (Exception e) {
            log.error("记录商品访问失败: productId={}, error={}", productId, e.getMessage(), e);
        }
    }

    @Override
    public Long getProductPV(Long productId) {
        try {
            String pvKey = PV_KEY_PREFIX + productId;
            return redisHyperLogLogService.size(pvKey);
        } catch (Exception e) {
            log.error("获取商品PV失败: productId={}, error={}", productId, e.getMessage(), e);
            return 0L;
        }
    }

    @Override
    public Long getProductUV(Long productId) {
        try {
            String uvKey = UV_KEY_PREFIX + productId;
            return redisHyperLogLogService.size(uvKey);
        } catch (Exception e) {
            log.error("获取商品UV失败: productId={}, error={}", productId, e.getMessage(), e);
            return 0L;
        }
    }

    @Override
    public Map<String, Object> getProductViewStats(Long productId) {
        Map<String, Object> stats = new HashMap<>();
        try {
            Long pv = getProductPV(productId);
            Long uv = getProductUV(productId);

            stats.put("productId", productId);
            stats.put("totalPV", pv);
            stats.put("totalUV", uv);
            stats.put("pvUvRatio", uv > 0 ? String.format("%.2f", (double) pv / uv) : "0.00");

            // 获取今日统计
            Map<String, Object> todayStats = getTodayProductViewStats(productId);
            stats.put("todayPV", todayStats.get("todayPV"));
            stats.put("todayUV", todayStats.get("todayUV"));
            stats.put("timestamp", System.currentTimeMillis());

            log.debug("获取商品访问统计: productId={}, stats={}", productId, stats);

        } catch (Exception e) {
            log.error("获取商品访问统计失败: productId={}, error={}", productId, e.getMessage(), e);
            stats.put("error", e.getMessage());
        }
        return stats;
    }

    @Override
    public Map<Long, Long> getBatchProductPV(Long... productIds) {
        Map<Long, Long> pvMap = new HashMap<>();
        try {
            for (Long productId : productIds) {
                Long pv = getProductPV(productId);
                pvMap.put(productId, pv);
            }
            log.debug("批量获取商品PV: productIds={}, result={}", productIds, pvMap);
        } catch (Exception e) {
            log.error("批量获取商品PV失败: productIds={}, error={}", productIds, e.getMessage(), e);
        }
        return pvMap;
    }

    @Override
    public Map<Long, Long> getBatchProductUV(Long... productIds) {
        Map<Long, Long> uvMap = new HashMap<>();
        try {
            for (Long productId : productIds) {
                Long uv = getProductUV(productId);
                uvMap.put(productId, uv);
            }
            log.debug("批量获取商品UV: productIds={}, result={}", productIds, uvMap);
        } catch (Exception e) {
            log.error("批量获取商品UV失败: productIds={}, error={}", productIds, e.getMessage(), e);
        }
        return uvMap;
    }

    @Override
    public void clearProductViewStats(Long productId) {
        try {
            String pvKey = PV_KEY_PREFIX + productId;
            String uvKey = UV_KEY_PREFIX + productId;

            redisHyperLogLogService.delete(pvKey);
            redisHyperLogLogService.delete(uvKey);

            log.info("清空商品访问统计: productId={}", productId);
        } catch (Exception e) {
            log.error("清空商品访问统计失败: productId={}, error={}", productId, e.getMessage(), e);
        }
    }

    @Override
    public Map<String, Object> getTodayProductViewStats(Long productId) {
        Map<String, Object> todayStats = new HashMap<>();
        try {
            String today = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
            String dailyPvKey = DAILY_PV_KEY_PREFIX + productId + ":" + today;
            String dailyUvKey = DAILY_UV_KEY_PREFIX + productId + ":" + today;

            Long todayPV = redisHyperLogLogService.size(dailyPvKey);
            Long todayUV = redisHyperLogLogService.size(dailyUvKey);

            todayStats.put("date", today);
            todayStats.put("todayPV", todayPV);
            todayStats.put("todayUV", todayUV);
            todayStats.put("todayPvUvRatio", todayUV > 0 ? String.format("%.2f", (double) todayPV / todayUV) : "0.00");

            log.debug("获取今日商品访问统计: productId={}, todayStats={}", productId, todayStats);

        } catch (Exception e) {
            log.error("获取今日商品访问统计失败: productId={}, error={}", productId, e.getMessage(), e);
            todayStats.put("error", e.getMessage());
        }
        return todayStats;
    }

    @Override
    public Map<String, Object> mergeProductViewStats(Long productId, String... dates) {
        Map<String, Object> mergedStats = new HashMap<>();
        try {
            // 构建临时合并键
            String tempPvKey = "temp:merged:pv:" + productId + ":" + System.currentTimeMillis();
            String tempUvKey = "temp:merged:uv:" + productId + ":" + System.currentTimeMillis();

            // 构建源键数组
            String[] pvKeys = new String[dates.length];
            String[] uvKeys = new String[dates.length];

            for (int i = 0; i < dates.length; i++) {
                pvKeys[i] = DAILY_PV_KEY_PREFIX + productId + ":" + dates[i];
                uvKeys[i] = DAILY_UV_KEY_PREFIX + productId + ":" + dates[i];
            }

            // 合并多个日期的统计数据
            redisHyperLogLogService.merge(tempPvKey, pvKeys);
            redisHyperLogLogService.merge(tempUvKey, uvKeys);

            // 获取合并后的结果
            Long mergedPV = redisHyperLogLogService.size(tempPvKey);
            Long mergedUV = redisHyperLogLogService.size(tempUvKey);

            // 清理临时键
            redisHyperLogLogService.delete(tempPvKey);
            redisHyperLogLogService.delete(tempUvKey);

            mergedStats.put("productId", productId);
            mergedStats.put("dateRange", String.join(",", dates));
            mergedStats.put("mergedPV", mergedPV);
            mergedStats.put("mergedUV", mergedUV);
            mergedStats.put("mergedPvUvRatio", mergedUV > 0 ? String.format("%.2f", (double) mergedPV / mergedUV) : "0.00");

            log.debug("合并商品访问统计: productId={}, dates={}, mergedStats={}",
                    productId, dates, mergedStats);

        } catch (Exception e) {
            log.error("合并商品访问统计失败: productId={}, dates={}, error={}",
                    productId, dates, e.getMessage(), e);
            mergedStats.put("error", e.getMessage());
        }
        return mergedStats;
    }
}